home *** CD-ROM | disk | FTP | other *** search
/ Skunkware 98 / Skunkware 98.iso / osr5 / sco / scripts / msgs < prev    next >
Encoding:
Korn shell script  |  1997-08-26  |  9.7 KB  |  382 lines

  1. #!/bin/ksh
  2. # @(#) msgs.ksh 1.1 97/06/09
  3. # 91/09/23 john h. dubois iii (john@armory.com)
  4. # 91/10/12 added interactive option to go to a particular message
  5. # 91/11/03 added -n option
  6. # 92/01/30 added header commands, keep track of firstmsg,
  7. #       assorted other improvements
  8. # 92/01/31 fixed IFS prob by making it local to pager()
  9. #          added $ to header range options
  10. # 92/03/02 added test for readability of range file.
  11. # 92/03/10 added save-message feature
  12. # 92/07/08 added / to message options
  13. # 92/09/20 Skip up to From: line
  14. # 92/09/26 Added -e to egrep line
  15. # 93/02/02 Check what messages actually exist when -q is given
  16. # 93/02/04 Allow ranges for most commands
  17. # 93/02/22 Fixed n to actually skip messages
  18. # 93/04/01 Added $ command line option
  19. # 93/04/08 Make / search files in numerical order
  20. # 93/09/16 Added -s
  21. # 93/09/21 Added -w & -n
  22. # 93/12/28 Added -i to egrep args.  
  23. #          Eliminated trailing space added to search args.
  24. # 94/05/13 Be annoying if there are old unread messages.
  25. # 97/06/09 Deal with bad .msgsrc file gracefully.
  26.  
  27. # This utility operates on a collection of message files in a publicly
  28. # accessible directory named /usr/spool/msgs.  The message files should be
  29. # in RFC822 format, with at least a From: and Subject: line in the header.
  30. # The filenames should be positive integer numbers.
  31. # In the /usr/spool/msgs directory, there should also be a file named "range".
  32. # The range file should contain two numbers separated by whitespace, with the
  33. # numbers being the first and last message numbers.
  34.  
  35. alias istrue="test 0 -ne"
  36. alias isfalse="test 0 -eq"
  37.  
  38. typeset -i firstmsg lastmsg unread=0 highestread neverread lines lastmsgread=0
  39. typeset -i debug=0
  40.  
  41. rcfile=$HOME/.msgsrc
  42. msgdir=/usr/spool/msgs
  43. name=${0##*/}
  44.  
  45. function waitexit {
  46.     if istrue wait; then
  47.     print -n "Press <return> to exit msgs..."
  48.     read
  49.     fi
  50.     exit 0
  51. }
  52.  
  53. # Usage: pager [filename]
  54. # If no filename is given, pager pages stdin.
  55. # If a filename is given, it is taken to be a message and the header lines
  56. # up to, but not including, the From: line are skipped, if possible.
  57. # If the input is <= $lines lines long, it will paged by $PAGER.
  58. # Otherwise, it will be printed directly.
  59. function pager {
  60.     typeset input msg 
  61.     typeset -i count=0 infile=$1 FromLine=0
  62.     typeset IFS=    # Avoid losing leading & trailing space on read
  63.     if [ $# -eq 0 ]; then
  64.     while [ count -le lines ] && read input; do
  65.         msg="$msg
  66. $input"
  67.         let count+=1
  68.     done
  69.     if [ count -gt lines ]; then
  70.         (
  71.         print -r "$msg"
  72.         while read input; do
  73.         print -r "$input"
  74.         done ) | $PAGER
  75.     else
  76.         print -r "$msg"
  77.     fi
  78.     else
  79.     while [ count -le lines ] && read input; do
  80.         if isfalse count; then
  81.         let FromLine+=1
  82.         if [[ "$input" = From:* ]]; then
  83.             msg="$msg
  84. $input"
  85.             count=1
  86.         fi
  87.         else
  88.         let count+=1
  89.         msg="$msg
  90. $input"
  91.         fi
  92.     done < "$infile"
  93.     if [ count -gt lines ]; then
  94.         if [[ $PAGER = *?(more|less|pg) ]]; then
  95.         $PAGER +$FromLine "$infile"
  96.         else
  97.         $PAGER "$infile"
  98.         fi
  99.     else
  100.         print -r "$msg"
  101.     fi
  102.     fi
  103. }
  104.  
  105. # Usage: headers first-last
  106. # Prints the headers for messages
  107. function headers {
  108.     typeset -i range1 range2
  109.     typeset msglist range=$1
  110.  
  111.     cd $msgdir
  112.     range1=${range%-*}
  113.     range2=${range#*-}
  114.     while [ range1 -le range2 ]; do
  115.     [ -f $range1 ] && msglist="$msglist $range1"
  116.     let range1+=1
  117.     done
  118.     if [ -z "$msglist" ]; then
  119.     echo "$name: No messages."
  120.     else
  121.     # Include /dev/null so that there will always be at least
  122.     # two files (if there are any at all) so that filenames
  123.     # (message numbers) will be prepended to Subject lines
  124.     egrep '^Subject: ' /dev/null $msglist | sed s/:Subject:// | pager
  125.     fi
  126. }
  127.  
  128. function chknums {
  129.     if [ $# -eq 0 -o $# -eq 1 -a "$1" -gt lastmsg ]; then
  130.     print -u2 "$name: No message numbers given."
  131.     return 1
  132.     else
  133.     return 0
  134.     fi
  135. }
  136.  
  137. # Usage: action cmd args ranges
  138. function action {
  139.     typeset cmd=$1 args=$2 message msglist
  140.     ret=0
  141.     shift 2
  142.  
  143.     case $cmd in
  144.     d)    chknums "$@" && rm $* && echo "Removed $*.";;
  145.     n)    ;;
  146.     s)    msglist=$*
  147.     chknums "$@" || return 1
  148.     set -- $args
  149.     case $# in
  150.     0) echo "$name: No filename given."
  151.         return 1;;
  152.     1)
  153.         cd $OPWD
  154.         [ -f "$1" ] && act=appended || act=written
  155.         (cd $msgdir; cat $msglist) >> $1 &&
  156.         echo "Message(s) $msglist $act to file \"$1\"" ||
  157.         ret=1
  158.         cd $msgdir
  159.         return $ret;;
  160.     *) echo "$name: Too many arguments."
  161.         return 1;
  162.     esac;;
  163.     x)    exit;;
  164.     y)    chknums "$@" &&
  165.     for message; do
  166.         pager $message
  167.     done;;
  168.     \?) echo \
  169. "y or <cr>: yes, read the message
  170. n: no, skip the message
  171. q: quit
  172. s <filename>: save the message to file <filename>
  173. x: exit without updating .msgsrc file
  174. h: print headers
  175. /<pattern>: find lines in messages that match <pattern>
  176. ?: print this help
  177. nnn: read message number nnn"
  178.         ;;
  179.     h)  chknums "$@" &&
  180.     egrep '^Subject: ' /dev/null $* | sed s/:Subject:// | pager
  181.     ;;
  182.     /*) if [ "$cmd" != / ]; then
  183.         [ -n "$args" ] && args="${cmd#/} $args" || args="${cmd#/}"
  184.     fi
  185.     shift
  186.     chknums "$@" || return 1
  187.     if [ $# -eq 0 ]; then
  188.         typeset -i pos=1
  189.         typeset pat=
  190.         set -A Files
  191.         while [ pos -le 5 ]; do
  192.         pat="$pat[0-9]"
  193.         set -- $pat
  194.         [ -r "$1" ] && set -A Files ${Files[*]} $*
  195.         let pos+=1
  196.         done
  197.         set -- ${Files[*]}
  198.     fi
  199.     egrep -i "$args" /dev/null $* | pager
  200.     ;;
  201.     *)  echo "$name: Invalid command.";
  202.         return 1;;
  203.     esac
  204. }
  205.  
  206. [ -f $rcfile -a ! -r $rcfile ] && exit
  207. if [ ! -r $msgdir/range ]; then
  208.     print -u2 "$name: Cannot open range file."
  209.     exit
  210. fi
  211.  
  212. read firstmsg lastmsg < $msgdir/range
  213.  
  214. if [ -f $rcfile ]; then
  215.     read lastmsgread < $rcfile || {
  216.     print "Bad last-message-read in your $rcfile file; removing it..."
  217.     rm -f -- $rcfile
  218.     neverread=1
  219.     }
  220. else
  221.     neverread=1
  222. fi 2>/dev/null
  223.  
  224. [ firstmsg -gt lastmsgread ] && lastmsgread=firstmsg-1
  225.  
  226. highestread=lastmsgread
  227. typeset -i wait=0 noquit=0 MsgAge
  228.  
  229. OPWD=$PWD
  230. cd $msgdir
  231.  
  232. for arg; do
  233.     case "$arg" in
  234.     -q) 
  235.     typeset -i curmsg=$lastmsgread+1
  236.     # Count unread messages
  237.     let lastmsgread+=1
  238.     while [ lastmsgread -le lastmsg ]; do
  239.         [ -f $msgdir/$lastmsgread ] && let unread+=1
  240.         let lastmsgread+=1
  241.     done
  242.     case $unread in
  243.     0) ;;
  244.     1) echo "There is one new system message.";;
  245.     *) echo "There are $unread new system messages.";;
  246.     esac
  247.     if istrue neverread || [ unread -gt 2 ]; then
  248.         # Be annoying if there are old unread messages.
  249.         if type stat unixtime > /dev/null; then
  250.         # Find oldest unread message
  251.         istrue debug && set -x
  252.         istrue debug && print $curmsg $lastmsg
  253.         while [ curmsg -le lastmsg -a ! -r $curmsg ]; do
  254.             curmsg=curmsg+1
  255.         done
  256.         if [ curmsg -le lastmsg ]; then
  257.             MsgAge="($(unixtime)-$(stat -nfm $curmsg))/86400"
  258.             [ $MsgAge -gt 60 ] &&
  259.             print "\007\007\007It is important to read them."
  260.         fi
  261.         fi
  262.         echo 'Type "msgs" to read the system messages.'
  263.     fi
  264.     exit $unread;;
  265.     +([0-9]))
  266.     lastmsgread=$1-1;;
  267.     -+([0-9]))
  268.     lastmsgread=lastmsg$1;;
  269.     $)
  270.     lastmsgread=lastmsg-1;;
  271.     -s)
  272.     [ lastmsgread -lt lastmsg ] && headers $((lastmsgread+1))-$lastmsg
  273.     waitexit;;
  274.     -h)
  275.     echo \
  276. "$name: read system messages.
  277. Usage: $name [-wqnhs] [[-]<num>]
  278. If a number is given as an argument, msgs will take it to be the first
  279. message to read.  If the number has a '-' in front of it, msgs will make the
  280. first message to read be the last system message minus the number given.
  281. Options:
  282. -q: Print a message if there are unread system messages.
  283.     Otherwise exit without printing anything.
  284.     The exit value is equal to the number of unread system messages.
  285. -s: Print the subjects of the messages that would be read.
  286. -h: Print this help.
  287. -n: Do not quit after printing the last message.
  288.     This can be used to read messages even if all messages have been read.
  289. -w: Wait after printing the last message until return is pressed,
  290.     for use with a windowing environment."
  291.     waitexit;;
  292.     -w)
  293.     wait=1;;
  294.     -x)
  295.     debug=1;;
  296.     -n)
  297.     noquit=1;;
  298.     *)
  299.     echo "$name: $arg: Invalid argument.  Use -h for help."
  300.     exit 1
  301.     ;;
  302.     esac
  303. done
  304.  
  305. [ -z "$PAGER" ] && PAGER=less
  306.  
  307. if [ lastmsgread -ge lastmsg ]; then
  308.     echo "No new messages."
  309.     isfalse noquit && waitexit
  310. fi
  311.  
  312. lines=$(tput lines)-4
  313.  
  314. typeset -i curmsg=$lastmsgread+1 range1 range2
  315.  
  316. function isrange {
  317. [[ "$1" = @(+([0-9])|-+([0-9])|+([0-9])-+([0-9])|+([0-9])-|+([0-9])-\$|\$) ]]
  318. }
  319.  
  320. while [ curmsg -le lastmsg ] || istrue noquit; do
  321.     if [ ! -r $curmsg -a curmsg -le lastmsg ]; then
  322.     curmsg=curmsg+1
  323.     continue
  324.     fi
  325.     if [ curmsg -le lastmsg ]; then
  326.     subject=$(egrep '^Subject: ' $curmsg)
  327.     echo -n "\nMessage #$curmsg\n$subject\nRead [ynqsxh/?]? "
  328.     else
  329.     echo -n "\n[qsxh/?]? "
  330.     fi
  331.     read line
  332.     # response format: [cmd] [range ...] [filename]
  333.     [ -z "$line" ] && line=y
  334.     set -- $line
  335.     if isrange $1; then
  336.     cmd=y
  337.     else
  338.     cmd=$1
  339.     shift
  340.     fi
  341.     [ "$cmd" = q ] && break
  342.     if [ "$cmd" = h -a $# = 0 ]; then
  343.     [ curmsg -gt lastmsg ] && set -- 1- || set -- $curmsg-
  344.     fi
  345.     msglist= range=
  346.     while isrange $1; do
  347.     range=$1
  348.     case $range in
  349.     +([0-9])) range1=$range range2=$range;;
  350.     +([0-9])-+([0-9])) range1=${range%-*} range2=${range#*-};;
  351.     -+([0-9])) range1=curmsg$range range2=lastmsg;;
  352.     +([0-9])-) range1=${range%-} range2=lastmsg;;
  353.     +([0-9])-\$) range1=${range%-*} range2=lastmsg;;
  354.     \$) range1=lastmsg range2=lastmsg;;
  355.     *) echo "Invalid range: $range."; continue;;
  356.     esac
  357.     rangemsgs=
  358.     while [ range1 -le range2 ]; do
  359.         [ -r $range1 ] && rangemsgs="$rangemsgs $range1"
  360.         let range1+=1
  361.     done
  362.     if [ -z "$rangemsgs" ]; then
  363.         echo "No messages in range '$1'."
  364.     else
  365.         msglist="$msglist $rangemsgs"
  366.     fi
  367.     shift
  368.     done
  369.     [ -z "$range" ] && msglist=$curmsg
  370.     [ -z "$msglist" ] && continue
  371.     action "$cmd" "$*" $msglist
  372.     [[ curmsg -gt highestread ]] && highestread=curmsg
  373.     if [[ $cmd = [ny] ]]; then
  374.     set -- $msglist
  375.     shift $(($#-1))
  376.     curmsg=$1+1
  377.     fi
  378. done
  379. [ $highestread -gt lastmsg ] && highestread=$lastmsg
  380. echo $highestread > $rcfile
  381. waitexit
  382.